/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.controller.evaluation.prepare.course;

import cn.ac.nercis.pes.common.utils.DataUtils;
import cn.ac.nercis.pes.community.component.dialog.MessageDialog;
import cn.ac.nercis.pes.community.component.dialog.MessageType;
import cn.ac.nercis.pes.community.controller.base.GlobalEventHandle;
import cn.ac.nercis.pes.community.controller.base.InitEvalDataLoad;
import cn.ac.nercis.pes.community.manager.RealTimeSaveManager;
import cn.ac.nercis.pes.community.utils.*;
import cn.ac.nercis.pes.model.dto.evaluation.prepare.EvaluationStageDTO;
import cn.ac.nercis.pes.service.evaluation.EvaluationProcessService;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.StackPane;
import lombok.extern.slf4j.Slf4j;

import java.net.URL;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;

/**
 * 测评过程（快捷）管理控制器
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class EvalProcessFastController implements Initializable, GlobalEventHandle, InitEvalDataLoad {

    @FXML
    private StackPane page;
    @FXML
    private Button saveButton;

    @FXML
    private DatePicker prepareStartDP;
    @FXML
    private DatePicker prepareEndDP;
    @FXML
    private DatePicker planningStartDP;
    @FXML
    private DatePicker planningEndDP;
    @FXML
    private DatePicker evaluationStartDP;
    @FXML
    private DatePicker evaluationEndDP;
    @FXML
    private DatePicker reportStartDP;
    @FXML
    private DatePicker reportEditDP;

    private final EvaluationProcessService processService;
    private final RealTimeSaveManager realTimeSaveManager = new RealTimeSaveManager(this::realTimeSave);
    private String currentSystemId;
    private EvaluationStageDTO evaluationStage;

    public EvalProcessFastController() {
        this.processService = SpringUtils.getBean(EvaluationProcessService.class);
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        saveButton.setGraphic(IconUtils.getGlyph("save-button-icon","btn-icon"));
        GuiStore.applyQuickSave(this.page,this::onGlobalSave);
        realTimeSaveManager.listenerDateChange(prepareStartDP,prepareEndDP,planningStartDP,planningEndDP,
                evaluationStartDP,evaluationEndDP,reportStartDP,reportEditDP);
    }

    @Override
    public void initializeData(String systemId) {
        LogUtils.info(log, "初始化测评过程（快捷）信息...");
        this.currentSystemId = systemId;
        loadEvaluationState();
    }

    @FXML
    public void onFinishSave(){
        LogUtils.info(log, "执行保存操作...");
        saveEvalProcess(false);
    }

    @Override
    public void onGlobalSave() {
        LogUtils.info(log, "执行快捷保存操作...");
        saveEvalProcess(false);
    }

    public void realTimeSave(){
        LogUtils.info(log, "执行即时保存操作...");
        saveEvalProcess(true);
    }

    private void loadEvaluationState() {
        LogUtils.info(log, "加载测评过程（快捷）信息...");
        LogUtils.info(log, "请求数据：{}", this.currentSystemId);
        CompletableFuture.supplyAsync(() -> this.processService.getEvaluationStage(this.currentSystemId))
                .thenAccept(res -> Platform.runLater(() -> loadContent(res)))
                .exceptionally((ex) -> {
                    log.error("加载测评过程（快捷）信息出错!", ex);
                    return null;
                });
    }

    private void loadContent(EvaluationStageDTO stage){
        this.realTimeSaveManager.setEnable(false);
        this.evaluationStage = stage;

        this.prepareStartDP.setValue(stage.getPreparationStartDate());
        this.prepareEndDP.setValue(stage.getPreparationEndDate());
        this.planningStartDP.setValue(stage.getCompilationStartDate());
        this.planningEndDP.setValue(stage.getCompilationEndDate());
        this.evaluationStartDP.setValue(stage.getEvaluationStartDate());
        this.evaluationEndDP.setValue(stage.getEvaluationEndDate());
        this.reportStartDP.setValue(stage.getAnalysisStartDate());
        this.reportEditDP.setValue(stage.getAnalysisEndDate());

        this.realTimeSaveManager.setEnable(true);
    }

    private void saveEvalProcess(boolean isRealTime) {
        if (!this.validContent()) {
            return;
        }
        evaluationStage.setPreparationStartDate(this.prepareStartDP.getValue());
        evaluationStage.setPreparationEndDate(this.prepareEndDP.getValue());
        evaluationStage.setCompilationStartDate(this.planningStartDP.getValue());
        evaluationStage.setCompilationEndDate(this.planningEndDP.getValue());
        evaluationStage.setEvaluationStartDate(this.evaluationStartDP.getValue());
        evaluationStage.setEvaluationEndDate(this.evaluationEndDP.getValue());
        evaluationStage.setAnalysisStartDate(this.reportStartDP.getValue());
        evaluationStage.setAnalysisEndDate(this.reportEditDP.getValue());
        LogUtils.info(log, "保存测评过程（快捷）信息...");
        LogUtils.record(log, "请求数据：{}", evaluationStage);
        CompletableFuture.supplyAsync(() -> this.processService.saveEvaluationState(evaluationStage))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess() && !isRealTime) {
                        AppUtils.showMessageDialog("保存成功",MessageType.SUCCESS,this.page);
                    } else {
                        if(isRealTime){
                            log.error("即时保存失败：{}",res.getMsg());
                            LogUtils.record(log,"保存数据：{}",evaluationStage);
                        }else{
                            AppUtils.showMessageDialog(res.getMsg(),MessageType.FAIL,this.page);
                        }
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("保存测评过程（快捷）信息出错!", ex);
                    return null;
                });
    }

    private boolean validContent(){
        if(!prepareValid()){
            return false;
        }
        if(!planningValid()){
            return false;
        }
        if(!evaluationValid()){
            return false;
        }
        return reportValid();
    }

    private boolean prepareValid(){
        if(Objects.isNull(prepareStartDP.getValue())
                || Objects.isNull(prepareEndDP.getValue())){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("准备过程，测评计划不允许为空")
                    .build().show();
            return false;
        }
        long between =  DataUtils.between(prepareStartDP.getValue(),
                prepareEndDP.getValue(), ChronoUnit.DAYS);
        if(between < 1){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("准备过程，测评计划结束日期必须大于开始日期")
                    .build().show();
            return false;
        }
        return true;
    }

    private boolean planningValid(){
        if(Objects.isNull(planningStartDP.getValue())
                || Objects.isNull(planningEndDP.getValue())){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("方案编制过程，测评计划不允许为空")
                    .build().show();
            return false;
        }
        long between =  DataUtils.between(planningStartDP.getValue(),
                planningEndDP.getValue(), ChronoUnit.DAYS);
        if(between < 1){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("方案编制过程，测评计划结束日期必须大于开始日期")
                    .build().show();
            return false;
        }
        return true;
    }

    private boolean evaluationValid(){
        if(Objects.isNull(evaluationStartDP.getValue())
                || Objects.isNull(evaluationEndDP.getValue())){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("测评实施过程，测评计划不允许为空")
                    .build().show();
            return false;
        }
        long between =  DataUtils.between(evaluationStartDP.getValue(),
                evaluationEndDP.getValue(), ChronoUnit.DAYS);
        if(between < 1){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("测评实施过程，测评计划结束日期必须大于开始日期")
                    .build().show();
            return false;
        }
        return true;
    }

    private boolean reportValid(){
        if(Objects.isNull(reportStartDP.getValue())
                || Objects.isNull(reportEditDP.getValue())){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("分析与报告编制过程，测评计划不允许为空")
                    .build().show();
            return false;
        }
        long between =  DataUtils.between(reportStartDP.getValue(),
                reportEditDP.getValue(), ChronoUnit.DAYS);
        if(between < 1){
            MessageDialog.builder()
                    .withContainer(this.page)
                    .withType(MessageType.WARN).withMessage("分析与报告编制过程，测评计划结束日期必须大于开始日期")
                    .build().show();
            return false;
        }
        return true;
    }

}